﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XNAViewerSample.Physics
{
    public abstract class Integrators
    {
        protected float fixedTimeStep;

        public float FixedTimeStep
        {
            get { return fixedTimeStep; }
            set { fixedTimeStep = value; }
        }

        public Integrators()
        {
            //set the fixed time step to target elapsed time (default at 1/60)
            //fixedTimeStep = (float)game.TargetElapsedTime.TotalSeconds;
        }

        public abstract void Integrate(Vector3 acceleration, SoftBodyObjects sbObject, GameTime gameTime);
    }

    public sealed class ForwardEulerIntegrator : Integrators
    {
        public ForwardEulerIntegrator()
            : base() { }

        public override void Integrate(Vector3 acceleration, SoftBodyObjects sbObject, GameTime gameTime)
        {
            fixedTimeStep = (float)gameTime.ElapsedGameTime.TotalSeconds;

            //calculate new velocity using the acceleration at current time
            sbObject.CurrVelocity += acceleration * fixedTimeStep;
            //calculate new position using the velocity at current time
            sbObject.CurrPosition += sbObject.CurrVelocity * fixedTimeStep;

        }
    }

    public sealed class VerletNoVelocityIntegrator : Integrators
    {
        private float drag;

        public float Drag
        {
            get { return drag; }
            set
            {
                if (value < 0 || value > 1)
                {
                    throw new ArgumentException("Air resistance must be between 0 and 1");
                }
                drag = value;
            }
        }

        public VerletNoVelocityIntegrator() : this(0.005f) { }

        public VerletNoVelocityIntegrator(float drag)
            : base()
        {
            this.drag = drag;
        }

        Vector3 newPosition;
        public override void Integrate(Vector3 acceleration, SoftBodyObjects sbObject, GameTime gameTime)
        {
            fixedTimeStep = (float)gameTime.ElapsedGameTime.TotalSeconds;

            newPosition = (2 - drag) * sbObject.CurrPosition
                - (1 - drag) * sbObject.PrevPosition
                + acceleration * fixedTimeStep * fixedTimeStep;

            sbObject.PrevPosition = sbObject.CurrPosition;
            sbObject.CurrPosition = newPosition;
        }
    }

}
